/**
 * layer
 * 通用 Web 弹出层组件
 */

import { layui } from '../core/layui.js';
import { lay } from '../core/lay.js';
import { i18n } from '../core/i18n.js';
import $ from 'jquery';

var win;
var ready = {
  config: {
    removeFocus: true,
  },
  end: {},
  beforeEnd: {},
  events: { resize: {} },
  minStackIndex: 0,
  minStackArr: [],
  // 五种原始层模式
  type: ['dialog', 'page', 'iframe', 'loading', 'tips'],

  // 获取节点的 style 属性值
  getStyle: function (node, name) {
    var style = node.currentStyle
      ? node.currentStyle
      : window.getComputedStyle(node, null);
    return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](
      name,
    );
  },
};

// 默认内置方法。
var layer = {
  ie: (function () {
    // ie 版本
    var agent = navigator.userAgent.toLowerCase();
    return !!window.ActiveXObject || 'ActiveXObject' in window
      ? (agent.match(/msie\s(\d+)/) || [])[1] || '11' // 由于 ie11 并没有 msie 的标识
      : false;
  })(),
  config: function (options) {
    options = options || {};
    layer.cache = ready.config = $.extend({}, ready.config, options);
    typeof options.extend === 'string' && (options.extend = [options.extend]);

    return this;
  },

  // 主体 CSS 等待事件（已弃用）
  ready: function (callback) {
    typeof callback === 'function' && callback();
    return this;
  },

  // 各种快捷引用
  alert: function (content, options, yes) {
    var type = typeof options === 'function';
    if (type) yes = options;
    return layer.open(
      $.extend(
        {
          content: content,
          yes: yes,
        },
        type ? {} : options,
      ),
    );
  },

  confirm: function (content, options, yes, cancel) {
    var type = typeof options === 'function';
    if (type) {
      cancel = yes;
      yes = options;
    }
    return layer.open(
      $.extend(
        {
          content: content,
          btn: [i18n.$t('layer.confirm'), i18n.$t('layer.cancel')],
          yes: yes,
          btn2: cancel,
        },
        type ? {} : options,
      ),
    );
  },

  msg: function (content, options, end) {
    // 最常用提示层
    var type = typeof options === 'function',
      rskin = ready.config.skin;
    var skin = (rskin ? rskin + ' ' + rskin + '-msg' : '') || 'layui-layer-msg';
    var anim = doms.anim.length - 1;
    if (type) end = options;
    return layer.open(
      $.extend(
        {
          content: content,
          time: 3000,
          shade: false,
          skin: skin,
          title: false,
          closeBtn: false,
          btn: false,
          resize: false,
          end: end,
          removeFocus: false,
        },
        type && !ready.config.skin
          ? {
              skin: skin + ' layui-layer-hui',
              anim: anim,
            }
          : (function () {
              options = options || {};
              if (
                options.icon === -1 ||
                (options.icon === undefined && !ready.config.skin)
              ) {
                options.skin = skin + ' ' + (options.skin || 'layui-layer-hui');
              }
              return options;
            })(),
      ),
    );
  },

  load: function (icon, options) {
    return layer.open(
      $.extend(
        {
          type: 3,
          icon: icon || 0,
          resize: false,
          shade: 0.01,
          removeFocus: false,
        },
        options,
      ),
    );
  },

  tips: function (content, follow, options) {
    return layer.open(
      $.extend(
        {
          type: 4,
          content: [content, follow],
          closeBtn: false,
          time: 3000,
          shade: false,
          resize: false,
          fixed: false,
          maxWidth: 260,
          removeFocus: false,
        },
        options,
      ),
    );
  },
};

var Class = function (setings) {
  var that = this,
    creat = function () {
      that.creat();
    };
  // TODO 临时的同步方案
  ready.config.title = i18n.$t('layer.defaultTitle');
  that.index = layer.index = lay.autoIncrementer('layer');
  that.config.maxWidth = $(win).width() - 15 * 2; // 初始最大宽度：当前屏幕宽，左右留 15px 边距
  that.config = $.extend({}, that.config, ready.config, setings);
  document.body
    ? creat()
    : setTimeout(function () {
        creat();
      }, 30);
};

Class.pt = Class.prototype;

// 缓存常用字符
var doms = [
  'layui-layer',
  '.layui-layer-title',
  '.layui-layer-main',
  '.layui-layer-dialog',
  'layui-layer-iframe',
  'layui-layer-content',
  'layui-layer-btn',
  'layui-layer-close',
];

// 内置动画类
doms.anim = {
  // 旧版动画
  0: 'layer-anim-00',
  1: 'layer-anim-01',
  2: 'layer-anim-02',
  3: 'layer-anim-03',
  4: 'layer-anim-04',
  5: 'layer-anim-05',
  6: 'layer-anim-06',

  // 滑出方向
  slideDown: 'layer-anim-slide-down',
  slideLeft: 'layer-anim-slide-left',
  slideUp: 'layer-anim-slide-up',
  slideRight: 'layer-anim-slide-right',
};

doms.SHADE = 'layui-layer-shade';
doms.MOVE = 'layui-layer-move';

var SHADE_KEY = 'LAYUI-LAYER-SHADE-KEY';
var RECORD_HEIGHT_KEY = 'LAYUI_LAYER_CONTENT_RECORD_HEIGHT';

// 默认配置
Class.pt.config = {
  type: 0,
  shade: 0.3,
  fixed: true,
  move: doms[1],
  title: i18n.$t('layer.defaultTitle'),
  offset: 'auto',
  area: 'auto',
  closeBtn: 1,
  icon: -1,
  time: 0, // 0 表示不自动关闭
  zIndex: 19891014,
  maxWidth: 360,
  anim: 0,
  isOutAnim: true, // 退出动画
  minStack: true, // 最小化堆叠
  moveType: 1,
  resize: true,
  scrollbar: true, // 是否允许浏览器滚动条
  tips: 2,
};

// 容器
Class.pt.vessel = function (conType, callback) {
  var that = this,
    times = that.index,
    config = that.config;
  var zIndex = config.zIndex + times,
    titype = typeof config.title === 'object';
  var ismax = config.maxmin && (config.type === 1 || config.type === 2);
  var titleHTML = config.title
    ? '<div class="layui-layer-title" style="' +
      (titype ? config.title[1] : '') +
      '">' +
      (titype ? config.title[0] : config.title) +
      '</div>'
    : '';

  config.zIndex = zIndex;
  callback(
    [
      // 遮罩
      config.shade
        ? '<div class="' +
          doms.SHADE +
          '" id="' +
          doms.SHADE +
          times +
          '" times="' +
          times +
          '" style="' +
          ('z-index:' + (zIndex - 1) + '; ') +
          '"></div>'
        : '',

      // 主体
      '<div class="' +
        doms[0] +
        (' layui-layer-' + ready.type[config.type]) +
        ((config.type == 0 || config.type == 2) && !config.shade
          ? ' layui-layer-border'
          : '') +
        ' ' +
        (config.skin || '') +
        '" id="' +
        doms[0] +
        times +
        '" type="' +
        ready.type[config.type] +
        '" times="' +
        times +
        '" showtime="' +
        config.time +
        '" conType="' +
        (conType ? 'object' : 'string') +
        '" style="z-index: ' +
        zIndex +
        '; width:' +
        config.area[0] +
        ';height:' +
        config.area[1] +
        ';position:' +
        (config.fixed ? 'fixed;' : 'absolute;') +
        '">' +
        (conType && config.type != 2 ? '' : titleHTML) +
        // 内容区
        '<div' +
        (config.id ? ' id="' + config.id + '"' : '') +
        ' class="layui-layer-content' +
        (config.type == 0 && config.icon !== -1 ? ' layui-layer-padding' : '') +
        (config.type == 3 ? ' layui-layer-loading' + config.icon : '') +
        '">' +
        // 表情或图标
        (function () {
          var face = [
            'layui-icon-tips',
            'layui-icon-success',
            'layui-icon-error',
            'layui-icon-question',
            'layui-icon-lock',
            'layui-icon-face-cry',
            'layui-icon-face-smile',
          ];

          var additFaceClass;

          // 动画类
          var animClass = 'layui-anim layui-anim-rotate layui-anim-loop';

          // 信息框表情
          if (config.type == 0 && config.icon !== -1) {
            // 加载（加载图标）
            if (config.icon == 16) {
              additFaceClass = 'layui-icon layui-icon-loading ' + animClass;
            }
            return (
              '<i class="layui-layer-face layui-icon ' +
              (additFaceClass || face[config.icon] || face[0]) +
              '"></i>'
            );
          }

          // 加载层图标
          if (config.type == 3) {
            var type = ['layui-icon-loading', 'layui-icon-loading-1'];
            // 风格 2
            if (config.icon == 2) {
              return (
                '<div class="layui-layer-loading-2 ' + animClass + '"></div>'
              );
            }
            return (
              '<i class="layui-layer-loading-icon layui-icon ' +
              (type[config.icon] || type[0]) +
              ' ' +
              animClass +
              '"></i>'
            );
          }

          return '';
        })() +
        (config.type == 1 && conType ? '' : config.content || '') +
        '</div>' +
        // 右上角按钮
        '<div class="layui-layer-setwin">' +
        (function () {
          var arr = [];

          // 最小化、最大化
          if (ismax) {
            arr.push('<span class="layui-layer-min"></span>');
            arr.push('<span class="layui-layer-max"></span>');
          }

          // 关闭按钮
          if (config.closeBtn) {
            arr.push(
              '<span class="layui-icon layui-icon-close ' +
                [
                  doms[7],
                  doms[7] +
                    (config.title
                      ? config.closeBtn
                      : config.type == 4
                        ? '1'
                        : '2'),
                ].join(' ') +
                '"></span>',
            );
          }

          return arr.join('');
        })() +
        '</div>' +
        // 底部按钮
        (config.btn
          ? (function () {
              var button = '';
              typeof config.btn === 'string' && (config.btn = [config.btn]);
              for (var i = 0, len = config.btn.length; i < len; i++) {
                button +=
                  '<a class="' +
                  doms[6] +
                  '' +
                  i +
                  '">' +
                  config.btn[i] +
                  '</a>';
              }
              return (
                '<div class="' +
                (function () {
                  var className = [doms[6]];
                  if (config.btnAlign)
                    className.push(doms[6] + '-' + config.btnAlign);
                  return className.join(' ');
                })() +
                '">' +
                button +
                '</div>'
              );
            })()
          : '') +
        (config.resize ? '<span class="layui-layer-resize"></span>' : '') +
        '</div>',
    ],
    titleHTML,
    $('<div class="' + doms.MOVE + '" id="' + doms.MOVE + '"></div>'),
  );
  return that;
};

// 创建骨架
Class.pt.creat = function () {
  var that = this;
  var config = that.config;
  var times = that.index;
  var content = config.content;
  var conType = typeof content === 'object';
  var body = $('body');

  var setAnim = function (layero) {
    // anim 兼容旧版 shift
    if (config.shift) {
      config.anim = config.shift;
    }

    // 为兼容 jQuery3.0 的 css 动画影响元素尺寸计算
    if (doms.anim[config.anim]) {
      var animClass = 'layer-anim ' + doms.anim[config.anim];
      layero
        .addClass(animClass)
        .one(
          'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend',
          function () {
            $(this).removeClass(animClass);
          },
        );
    }
  };

  // 若 id 对应的弹层已经存在，则不重新创建
  if (config.id && $('.' + doms[0]).find('#' + config.id)[0]) {
    return (function () {
      var layero = $('#' + config.id).closest('.' + doms[0]);
      var index = layero.attr('times');
      var options = layero.data('config');
      var elemShade = $('#' + doms.SHADE + index);

      var maxminStatus = layero.data('maxminStatus') || {};
      // 若弹层为最小化状态，则点击目标元素时，自动还原
      if (maxminStatus === 'min') {
        layer.restore(index);
      } else if (options.hideOnClose) {
        elemShade.show();
        layero.show();
        setAnim(layero);
        setTimeout(function () {
          elemShade.css({ opacity: elemShade.data(SHADE_KEY) });
        }, 10);
      }
    })();
  }

  // 是否移除活动元素的焦点
  if (config.removeFocus && document.activeElement) {
    document.activeElement.blur(); // 将原始的聚焦节点失焦
  }

  // 初始化 area 属性
  if (typeof config.area === 'string') {
    config.area = config.area === 'auto' ? ['', ''] : [config.area, ''];
  }

  switch (config.type) {
    case 0:
      config.btn = 'btn' in config ? config.btn : i18n.$t('layer.confirm');
      layer.closeAll('dialog');
      break;
    case 2:
      content = config.content = conType
        ? config.content
        : [config.content || '', 'auto'];
      config.content =
        '<iframe scrolling="' +
        (config.content[1] || 'auto') +
        '" allowtransparency="true" id="' +
        doms[4] +
        '' +
        times +
        '" name="' +
        doms[4] +
        '' +
        times +
        '" onload="this.className=\'\';" class="layui-layer-load" frameborder="0" src="' +
        config.content[0] +
        '"></iframe>';
      break;
    case 3:
      delete config.title;
      delete config.closeBtn;
      config.icon === -1 && config.icon === 0;
      layer.closeAll('loading');
      break;
    case 4:
      conType || (config.content = [config.content, 'body']);
      config.follow = config.content[1];
      config.content = config.content[0] + '<i class="layui-layer-TipsG"></i>';
      delete config.title;
      config.tips =
        typeof config.tips === 'object' ? config.tips : [config.tips, true];
      config.tipsMore || layer.closeAll('tips');
      break;
  }

  // 建立容器
  that
    .vessel(conType, function (html, titleHTML, moveElem) {
      body.append(html[0]);
      conType
        ? (function () {
            config.type == 2 || config.type == 4
              ? (function () {
                  $('body').append(html[1]);
                })()
              : (function () {
                  if (!content.parents('.' + doms[0])[0]) {
                    content
                      .data('display', content.css('display'))
                      .show()
                      .addClass('layui-layer-wrap')
                      .wrap(html[1]);
                    $('#' + doms[0] + times)
                      .find('.' + doms[5])
                      .before(titleHTML);
                  }
                })();
          })()
        : body.append(html[1]);
      $('#' + doms.MOVE)[0] || body.append((ready.moveElem = moveElem));

      that.layero = $('#' + doms[0] + times);
      that.shadeo = $('#' + doms.SHADE + times);

      config.scrollbar || ready.setScrollbar(times);
    })
    .auto(times);

  // 遮罩
  that.shadeo.css({
    'background-color': config.shade[1] || '#000',
    opacity: config.shade[0] || config.shade,
    transition: config.shade[2] || '',
  });
  that.shadeo.data(SHADE_KEY, config.shade[0] || config.shade);

  // 坐标自适应浏览器窗口尺寸
  config.type == 4
    ? that.tips()
    : (function () {
        that.offset();
        // 首次弹出时，若 css 尚未加载，则等待 css 加载完毕后，重新设定尺寸
        parseInt(
          ready.getStyle(document.getElementById(doms.MOVE), 'z-index'),
        ) ||
          (function () {
            that.layero.css('visibility', 'hidden');
            layer.ready(function () {
              that.offset();
              that.layero.css('visibility', 'visible');
            });
          })();
      })();

  // 若是固定定位，则跟随 resize 事件来自适应坐标
  if (config.fixed) {
    if (!ready.events.resize[that.index]) {
      ready.events.resize[that.index] = function () {
        that.resize();
      };
      // 此处 resize 事件不会一直叠加，当关闭弹层时会移除该事件
      win.on('resize', ready.events.resize[that.index]);
    }
  }

  // 记录配置信息
  that.layero.data('config', config);

  // 自动关闭
  config.time <= 0 ||
    setTimeout(function () {
      layer.close(that.index);
    }, config.time);

  that.move().callback();
  setAnim(that.layero);
};

// 当前实例的 resize 事件
Class.pt.resize = function () {
  var that = this;
  var config = that.config;

  that.offset();
  (/^\d+%$/.test(config.area[0]) || /^\d+%$/.test(config.area[1])) &&
    that.auto(that.index);
  config.type == 4 && that.tips();
};

// 自适应
Class.pt.auto = function (index) {
  var that = this,
    config = that.config,
    layero = $('#' + doms[0] + index);

  if (
    (config.area[0] === '' || config.area[0] === 'auto') &&
    config.maxWidth > 0
  ) {
    layero.outerWidth() > config.maxWidth && layero.width(config.maxWidth);
  }

  var area = [layero.innerWidth(), layero.innerHeight()];
  var titHeight = layero.find(doms[1]).outerHeight() || 0;
  var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0;
  var setHeight = function (elem) {
    elem = layero.find(elem);
    elem.height(
      area[1] -
        titHeight -
        btnHeight -
        2 * (parseFloat(elem.css('padding-top')) | 0),
    );
  };

  switch (config.type) {
    case 2:
      setHeight('iframe');
      break;
    default:
      if (config.area[1] === '' || config.area[1] === 'auto') {
        if (config.maxHeight > 0 && layero.outerHeight() > config.maxHeight) {
          area[1] = config.maxHeight;
          setHeight('.' + doms[5]);
        } else if (config.fixed && area[1] >= win.height()) {
          area[1] = win.height();
          setHeight('.' + doms[5]);
        }
      } else {
        setHeight('.' + doms[5]);
      }
      break;
  }

  return that;
};

// 计算坐标
Class.pt.offset = function () {
  var that = this,
    config = that.config,
    layero = that.layero;
  var coords = ready.updatePosition(layero, config);

  that.offsetTop = coords.offsetTop;
  that.offsetLeft = coords.offsetLeft;
};

// Tips
Class.pt.tips = function () {
  var that = this,
    config = that.config,
    layero = that.layero;
  var layArea = [layero.outerWidth(), layero.outerHeight()],
    follow = $(config.follow);
  if (!follow[0]) follow = $('body');
  var goal = {
      width: follow.outerWidth(),
      height: follow.outerHeight(),
      top: follow.offset().top,
      left: follow.offset().left,
    },
    tipsG = layero.find('.layui-layer-TipsG');

  var guide = config.tips[0];
  config.tips[1] || tipsG.remove();

  goal.autoLeft = function () {
    if (goal.left + layArea[0] - win.width() > 0) {
      goal.tipLeft = goal.left + goal.width - layArea[0];
      tipsG.css({ right: 12, left: 'auto' });
    } else {
      goal.tipLeft =
        goal.left - (goal.width * 0.75 < 21 ? 21 - goal.width * 0.5 : 0);
      goal.tipLeft = Math.max(goal.tipLeft, 0);
    }
  };

  // 辨别 tips 的方位
  // 21 为箭头大小 8*2 + 箭头相对父元素的top偏移 5
  goal.where = [
    function () {
      // 上
      goal.autoLeft();
      goal.tipTop = goal.top - layArea[1] - 10;
      tipsG
        .removeClass('layui-layer-TipsB')
        .addClass('layui-layer-TipsT')
        .css('border-right-color', config.tips[1]);
    },
    function () {
      // 右
      goal.tipLeft = goal.left + goal.width + 10;
      goal.tipTop =
        goal.top - (goal.height * 0.75 < 21 ? 21 - goal.height * 0.5 : 0);
      goal.tipTop = Math.max(goal.tipTop, 0);
      tipsG
        .removeClass('layui-layer-TipsL')
        .addClass('layui-layer-TipsR')
        .css('border-bottom-color', config.tips[1]);
    },
    function () {
      // 下
      goal.autoLeft();
      goal.tipTop = goal.top + goal.height + 10;
      tipsG
        .removeClass('layui-layer-TipsT')
        .addClass('layui-layer-TipsB')
        .css('border-right-color', config.tips[1]);
    },
    function () {
      // 左
      goal.tipLeft = goal.left - layArea[0] - 10;
      goal.tipTop =
        goal.top - (goal.height * 0.75 < 21 ? 21 - goal.height * 0.5 : 0);
      goal.tipTop = Math.max(goal.tipTop, 0);
      tipsG
        .removeClass('layui-layer-TipsR')
        .addClass('layui-layer-TipsL')
        .css('border-bottom-color', config.tips[1]);
    },
  ];
  goal.where[guide - 1]();

  /* 8*2为小三角形占据的空间 */
  if (guide === 1) {
    goal.top - (win.scrollTop() + layArea[1] + 8 * 2) < 0 && goal.where[2]();
  } else if (guide === 2) {
    win.width() - (goal.left + goal.width + layArea[0] + 8 * 2) > 0 ||
      goal.where[3]();
  } else if (guide === 3) {
    goal.top -
      win.scrollTop() +
      goal.height +
      layArea[1] +
      8 * 2 -
      win.height() >
      0 && goal.where[0]();
  } else if (guide === 4) {
    layArea[0] + 8 * 2 - goal.left > 0 && goal.where[1]();
  }

  layero.find('.' + doms[5]).css({
    'background-color': config.tips[1],
    'padding-right': config.closeBtn ? '30px' : '',
  });
  layero.css({
    left: goal.tipLeft - (config.fixed ? win.scrollLeft() : 0),
    top: goal.tipTop - (config.fixed ? win.scrollTop() : 0),
  });
};

// 拖拽层
Class.pt.move = function () {
  var that = this;
  var config = that.config;
  var _DOC = $(document);
  var layero = that.layero;
  var DATA_NAME = ['LAY_MOVE_DICT', 'LAY_RESIZE_DICT'];
  var moveElem = layero.find(config.move);
  var resizeElem = layero.find('.layui-layer-resize');

  // 给指定元素添加拖动光标
  if (config.move) moveElem.css('cursor', 'move');

  // 按下拖动元素
  moveElem.on('mousedown', function (e) {
    if (e.button) {
      return;
    } // 不是左键不处理
    var othis = $(this);
    var dict = {};

    if (config.move) {
      dict.layero = layero;
      dict.config = config;
      dict.offset = [
        e.clientX - parseFloat(layero.css('left')),
        e.clientY - parseFloat(layero.css('top')),
      ];

      othis.data(DATA_NAME[0], dict);
      ready.eventMoveElem = othis;
      ready.moveElem.css('cursor', 'move').show();
    }

    e.preventDefault();
  });

  // 按下右下角拉伸
  resizeElem.on('mousedown', function (e) {
    var othis = $(this);
    var dict = {};

    if (config.resize) {
      dict.layero = layero;
      dict.config = config;
      dict.offset = [e.clientX, e.clientY];
      dict.index = that.index;
      dict.area = [layero.outerWidth(), layero.outerHeight()];

      othis.data(DATA_NAME[1], dict);
      ready.eventResizeElem = othis;
      ready.moveElem.css('cursor', 'se-resize').show();
    }

    e.preventDefault();
  });

  // 拖动元素，避免多次调用实例造成事件叠加
  if (ready.docEvent) return that;
  _DOC
    .on('mousemove', function (e) {
      var dict, config, X, Y;

      // 拖拽移动
      if (ready.eventMoveElem) {
        dict = ready.eventMoveElem.data(DATA_NAME[0]) || {};
        config = dict.config;
        X = e.clientX - dict.offset[0];
        Y = e.clientY - dict.offset[1];

        var layero = dict.layero;
        var fixed = layero.css('position') === 'fixed';

        e.preventDefault();

        dict.stX = fixed ? 0 : win.scrollLeft();
        dict.stY = fixed ? 0 : win.scrollTop();

        // 控制元素不被拖出窗口外
        if (!config.moveOut) {
          var setRig = win.width() - layero.outerWidth() + dict.stX;
          var setBot = win.height() - layero.outerHeight() + dict.stY;
          X < dict.stX && (X = dict.stX);
          X > setRig && (X = setRig);
          Y < dict.stY && (Y = dict.stY);
          Y > setBot && (Y = setBot);
        }

        // 拖动时跟随鼠标位置
        layero.css({
          left: X,
          top: Y,
        });
      }

      // Resize
      if (ready.eventResizeElem) {
        dict = ready.eventResizeElem.data(DATA_NAME[1]) || {};
        config = dict.config;
        X = e.clientX - dict.offset[0];
        Y = e.clientY - dict.offset[1];

        e.preventDefault();

        // 拉伸宽高
        layer.style(dict.index, {
          width: dict.area[0] + X,
          height: dict.area[1] + Y,
        });

        config.resizing && config.resizing(dict.layero);
      }
    })
    .on('mouseup', function () {
      if (ready.eventMoveElem) {
        var dict = ready.eventMoveElem.data(DATA_NAME[0]) || {};
        var config = dict.config;

        ready.eventMoveElem.removeData(DATA_NAME[0]);
        delete ready.eventMoveElem;
        ready.moveElem.hide();
        config.moveEnd && config.moveEnd(dict.layero);
      }
      if (ready.eventResizeElem) {
        ready.eventResizeElem.removeData(DATA_NAME[1]);
        delete ready.eventResizeElem;
        ready.moveElem.hide();
      }
    });

  ready.docEvent = true; // 已给 document 执行全局事件
  return that;
};

Class.pt.btnLoading = function (btnElem, isLoading) {
  if (isLoading) {
    var loadingTpl =
      '<i class="layui-layer-btn-loading-icon layui-icon layui-icon-loading layui-anim layui-anim-rotate layui-anim-loop"></i>';
    if (btnElem.find('.layui-layer-btn-loading-icon')[0]) return;
    btnElem
      .addClass('layui-layer-btn-is-loading')
      .attr({ disabled: '' })
      .prepend(loadingTpl);
  } else {
    btnElem
      .removeClass('layui-layer-btn-is-loading')
      .removeAttr('disabled')
      .find('.layui-layer-btn-loading-icon')
      .remove();
  }
};

Class.pt.callback = function () {
  var that = this,
    layero = that.layero,
    config = that.config;
  that.openLayer();
  if (config.success) {
    if (config.type == 2) {
      layero.find('iframe').on('load', function () {
        config.success(layero, that.index, that);
      });
    } else {
      config.success(layero, that.index, that);
    }
  }

  // 按钮
  layero
    .find('.' + doms[6])
    .children('a')
    .on('click', function () {
      var btnElem = $(this);
      var index = btnElem.index();
      if (btnElem.attr('disabled')) return;

      // 若为异步按钮
      if (config.btnAsync) {
        var btnCallback =
          index === 0
            ? config.yes || config['btn1']
            : config['btn' + (index + 1)];
        that.loading = function (isLoading) {
          that.btnLoading(btnElem, isLoading);
        };

        if (btnCallback) {
          ready
            .promiseLikeResolve(
              btnCallback.call(config, that.index, layero, that),
            )
            .then(
              function (result) {
                if (result !== false) {
                  layer.close(that.index);
                }
              },
              function (reason) {
                reason !== undefined &&
                  window.console &&
                  window.console.error('layer error hint: ' + reason);
              },
            );
        } else {
          layer.close(that.index);
        }
      } else {
        // 普通按钮
        if (index === 0) {
          if (config.yes) {
            config.yes(that.index, layero, that);
          } else if (config['btn1']) {
            config['btn1'](that.index, layero, that);
          } else {
            layer.close(that.index);
          }
        } else {
          var close =
            config['btn' + (index + 1)] &&
            config['btn' + (index + 1)](that.index, layero, that);
          close === false || layer.close(that.index);
        }
      }
    });

  // 取消
  function cancel() {
    var close = config.cancel && config.cancel(that.index, layero, that);
    close === false || layer.close(that.index);
  }

  // 右上角关闭回调
  layero.find('.' + doms[7]).on('click', cancel);

  // 点遮罩关闭
  if (config.shadeClose) {
    that.shadeo.on('click', function () {
      layer.close(that.index);
    });
  }

  // 最小化
  layero.find('.layui-layer-min').on('click', function () {
    var min = config.min && config.min(layero, that.index, that);
    min === false || layer.min(that.index, config);
  });

  // 全屏/还原
  layero.find('.layui-layer-max').on('click', function () {
    if ($(this).hasClass('layui-layer-maxmin')) {
      layer.restore(that.index);
      config.restore && config.restore(layero, that.index, that);
    } else {
      layer.full(that.index, config);
      setTimeout(function () {
        config.full && config.full(layero, that.index, that);
      }, 100);
    }
  });

  config.end && (ready.end[that.index] = config.end);
  config.beforeEnd &&
    (ready.beforeEnd[that.index] = $.proxy(
      config.beforeEnd,
      config,
      layero,
      that.index,
      that,
    ));
};

// 需依赖原型的对外方法
Class.pt.openLayer = function () {
  var that = this;

  // 置顶当前窗口
  layer.zIndex = that.config.zIndex;
  layer.setTop = function (layero) {
    var setZindex = function () {
      layer.zIndex++;
      layero.css('z-index', layer.zIndex + 1);
    };
    layer.zIndex = parseInt(layero[0].style.zIndex);
    layero.on('mousedown', setZindex);
    return layer.zIndex;
  };
};

// 记录宽高坐标，用于还原
ready.record = function (layero) {
  if (!layero[0]) return window.console && console.error('index error');
  var type = layero.attr('type');
  var contentElem = layero.find('.layui-layer-content');
  var contentRecordHeightElem =
    type === ready.type[2] ? contentElem.children('iframe') : contentElem;
  var area = [
    layero[0].style.width || ready.getStyle(layero[0], 'width'),
    layero[0].style.height || ready.getStyle(layero[0], 'height'),
    layero.position().top,
    layero.position().left + parseFloat(layero.css('margin-left')),
  ];
  layero.find('.layui-layer-max').addClass('layui-layer-maxmin');
  layero.attr({ area: area });
  contentElem.data(
    RECORD_HEIGHT_KEY,
    ready.getStyle(contentRecordHeightElem[0], 'height'),
  );
};

// 设置页面滚动条
ready.setScrollbar = function () {
  doms.html.css('overflow', 'hidden');
};

// 恢复页面滚动条
ready.restScrollbar = function (index) {
  if (!doms.html.css('overflow')) return;

  // 关闭和大小化, layer-full 处理
  var targetEl = $('.' + doms[0]).filter(function () {
    var layero = $(this);
    var options = layero.data('config') || {};
    return (
      options.scrollbar === false &&
      layero.data('maxminStatus') !== 'min' &&
      layero.attr('times') !== String(index)
    );
  });
  if (targetEl.length === 0) {
    doms.html.css('overflow', '');
  }
};

// 类似 Promise.resolve
ready.promiseLikeResolve = function (value) {
  var deferred = $.Deferred();

  if (value && typeof value.then === 'function') {
    value.then(deferred.resolve, deferred.reject);
  } else {
    deferred.resolve(value);
  }
  return deferred.promise();
};

ready.updatePosition = function (layero, config) {
  var area = [layero.outerWidth(), layero.outerHeight()];
  var coords = {
    offsetTop: (win.height() - area[1]) / 2,
    offsetLeft: (win.width() - area[0]) / 2,
  };

  if (typeof config.offset === 'object') {
    coords.offsetTop = config.offset[0];
    coords.offsetLeft = config.offset[1] || coords.offsetLeft;
  } else if (config.offset !== 'auto') {
    if (config.offset === 't') {
      // 上
      coords.offsetTop = 0;
    } else if (config.offset === 'r') {
      // 右
      coords.offsetLeft = win.width() - area[0];
    } else if (config.offset === 'b') {
      // 下
      coords.offsetTop = win.height() - area[1];
    } else if (config.offset === 'l') {
      // 左
      coords.offsetLeft = 0;
    } else if (config.offset === 'lt') {
      // 左上
      coords.offsetTop = 0;
      coords.offsetLeft = 0;
    } else if (config.offset === 'lb') {
      // 左下
      coords.offsetTop = win.height() - area[1];
      coords.offsetLeft = 0;
    } else if (config.offset === 'rt') {
      // 右上
      coords.offsetTop = 0;
      coords.offsetLeft = win.width() - area[0];
    } else if (config.offset === 'rb') {
      // 右下
      coords.offsetTop = win.height() - area[1];
      coords.offsetLeft = win.width() - area[0];
    } else {
      coords.offsetTop = config.offset;
    }
  }

  if (!config.fixed) {
    coords.offsetTop = /%$/.test(coords.offsetTop)
      ? (win.height() * parseFloat(coords.offsetTop)) / 100
      : parseFloat(coords.offsetTop);
    coords.offsetLeft = /%$/.test(coords.offsetLeft)
      ? (win.width() * parseFloat(coords.offsetLeft)) / 100
      : parseFloat(coords.offsetLeft);
    coords.offsetTop += win.scrollTop();
    coords.offsetLeft += win.scrollLeft();
  }

  // 最小化窗口时的自适应
  if (layero.data('maxminStatus') === 'min') {
    coords.offsetTop = win.height() - (layero.find(doms[1]).outerHeight() || 0);
    coords.offsetLeft = layero.css('left');
  }

  // 设置坐标
  layero.css({
    top: coords.offsetTop,
    left: coords.offsetLeft,
  });

  return coords;
};

/**
 * 外部方法
 */

// 获取子 iframe 的 DOM
layer.getChildFrame = function (selector, index) {
  index = index || $('.' + doms[4]).attr('times');
  return $('#' + doms[0] + index)
    .find('iframe')
    .contents()
    .find(selector);
};

// 得到当前 iframe 层的索引，子 iframe 时使用
layer.getFrameIndex = function (name) {
  if (!name) return;
  return $('#' + name)
    .parents('.' + doms[4])
    .attr('times');
};

// iframe 层自适应宽高
layer.iframeAuto = function (index) {
  if (!index) return;
  var layero = $('#' + doms[0] + index);
  var options = layero.data('config');
  var iframeHeight = layer.getChildFrame('html', index).outerHeight();
  var titleHeight = layero.find(doms[1]).outerHeight() || 0;
  var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0;
  var maxHeight = 'maxHeight' in options ? options.maxHeight : win.height();
  if (maxHeight) {
    iframeHeight = Math.min(iframeHeight, maxHeight - titleHeight - btnHeight);
  }
  layero.css({ height: iframeHeight + titleHeight + btnHeight });
  layero.find('iframe').css({ height: iframeHeight });

  ready.updatePosition(layero, options);
};

// 重置 iframe url
layer.iframeSrc = function (index, url) {
  $('#' + doms[0] + index)
    .find('iframe')
    .attr('src', url);
};

// 设定层的样式
layer.style = function (index, options, limit) {
  var layero = $('#' + doms[0] + index);
  var contentElem = layero.find('.layui-layer-content');
  var type = layero.attr('type');
  var titHeight = layero.find(doms[1]).outerHeight() || 0;
  var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0;
  // var minLeft = layero.attr('minLeft');

  // loading 和 tips 层不允许更改
  if (type === ready.type[3] || type === ready.type[4]) {
    return;
  }

  if (!limit) {
    if (parseFloat(options.width) <= 260) {
      options.width = 260;
    }

    if (parseFloat(options.height) - titHeight - btnHeight <= 64) {
      options.height = 64 + titHeight + btnHeight;
    }
  }
  layero.css(options);
  btnHeight = layero.find('.' + doms[6]).outerHeight() || 0;

  if (type === ready.type[2]) {
    layero.find('iframe').css({
      height:
        (typeof options.height === 'number'
          ? options.height
          : layero.height()) -
        titHeight -
        btnHeight,
    });
  } else {
    contentElem.css({
      height:
        (typeof options.height === 'number'
          ? options.height
          : layero.height()) -
        titHeight -
        btnHeight -
        parseFloat(contentElem.css('padding-top')) -
        parseFloat(contentElem.css('padding-bottom')),
    });
  }
};

// 最小化
layer.min = function (index, options) {
  var layero = $('#' + doms[0] + index);
  var maxminStatus = layero.data('maxminStatus');

  if (maxminStatus === 'min') return; // 当前的状态是否已经是最小化
  if (maxminStatus === 'max') layer.restore(index); // 若当前为最大化，则先还原后再最小化

  layero.data('maxminStatus', 'min');
  options = options || layero.data('config') || {};

  var shadeo = $('#' + doms.SHADE + index);
  var elemMin = layero.find('.layui-layer-min');
  var titHeight = layero.find(doms[1]).outerHeight() || 0;
  var minLeft = layero.attr('minLeft'); // 最小化时的横坐标
  var hasMinLeft = typeof minLeft === 'string'; // 是否已经赋值过最小化坐标
  var left = hasMinLeft ? minLeft : 181 * ready.minStackIndex + 'px';
  var position = layero.css('position');
  var minWidth = 180; // 最小化时的宽度
  var settings = {
    width: minWidth,
    height: titHeight,
    position: 'fixed',
    overflow: 'hidden',
  };

  ready.record(layero); // 记录当前尺寸、坐标，用于还原

  // 简易最小化补位
  if (ready.minStackArr.length > 0) {
    left = ready.minStackArr[0];
    ready.minStackArr.shift();
  }

  // left 是否超出边界
  if (parseFloat(left) + minWidth > win.width()) {
    left =
      win.width() -
      minWidth -
      (function () {
        ready.minStackArr.edgeIndex = ready.minStackArr.edgeIndex || 0;
        return (ready.minStackArr.edgeIndex += 3);
      })();
    if (left < 0) left = 0;
  }

  // 是否堆叠在左下角
  if (options.minStack) {
    settings.left = left;
    settings.top = win.height() - titHeight;
    hasMinLeft || ready.minStackIndex++; // 若未赋值过最小化坐标，则最小化操作索引自增
    layero.attr('minLeft', left);
  }

  layero.attr('position', position);
  layer.style(index, settings, true);

  elemMin.hide();
  layero.attr('type') === 'page' && layero.find(doms[4]).hide();
  ready.restScrollbar(index);

  // 隐藏遮罩
  shadeo.hide();
};

// 还原
layer.restore = function (index) {
  var layero = $('#' + doms[0] + index);
  var shadeo = $('#' + doms.SHADE + index);
  var contentElem = layero.find('.layui-layer-content');
  var area = layero.attr('area').split(',');
  var type = layero.attr('type');
  var options = layero.data('config') || {};
  var contentRecordHeight = contentElem.data(RECORD_HEIGHT_KEY);

  layero.removeData('maxminStatus'); // 移除最大最小状态

  // 恢复原来尺寸
  layer.style(
    index,
    {
      width: area[0], // 数值或百分比
      height: area[1],
      top: parseFloat(area[2]),
      left: parseFloat(area[3]),
      position: layero.attr('position'),
      overflow: 'visible',
    },
    true,
  );

  layero.find('.layui-layer-max').removeClass('layui-layer-maxmin');
  layero.find('.layui-layer-min').show();
  type === 'page' && layero.find(doms[4]).show();

  // 恢复页面滚动条弹层打开时的状态
  options.scrollbar ? ready.restScrollbar(index) : ready.setScrollbar(index);

  // #1604
  if (contentRecordHeight !== undefined) {
    contentElem.removeData(RECORD_HEIGHT_KEY);
    var contentRecordHeightElem =
      type === ready.type[2] ? contentElem.children('iframe') : contentElem;
    contentRecordHeightElem.css({ height: contentRecordHeight });
  }

  // 恢复遮罩
  shadeo.show();
  // ready.events.resize[index](); // ?
};

// 全屏（最大化）
layer.full = function (index) {
  var layero = $('#' + doms[0] + index);
  var maxminStatus = layero.data('maxminStatus');

  if (maxminStatus === 'max') return; // 检查当前的状态是否已经是最大化
  if (maxminStatus === 'min') layer.restore(index); // 若当前为最小化，则先还原后再最大化

  layero.data('maxminStatus', 'max');
  ready.record(layero); // 记录当前尺寸、坐标

  ready.setScrollbar(index);

  setTimeout(function () {
    var isfix = layero.css('position') === 'fixed';
    layer.style(
      index,
      {
        top: isfix ? 0 : win.scrollTop(),
        left: isfix ? 0 : win.scrollLeft(),
        width: '100%',
        height: '100%',
      },
      true,
    );
    layero.find('.layui-layer-min').hide();
  }, 100);
};

// 改变 title
layer.title = function (name, index) {
  var title = $('#' + doms[0] + (index || layer.index)).find(doms[1]);
  title.html(name);
};

// 关闭 layer 总方法
layer.close = function (index, callback) {
  var layero = (function () {
    var closest = $('.' + doms[0])
      .children('#' + index)
      .closest('.' + doms[0]);
    return closest[0]
      ? ((index = closest.attr('times')), closest)
      : $('#' + doms[0] + index);
  })();
  var type = layero.attr('type');
  var options = layero.data('config') || {};
  var hideOnClose = options.id && options.hideOnClose; // 是否关闭时移除弹层容器

  if (!layero[0]) return;

  var executor = function () {
    // 关闭动画
    var closeAnim =
      {
        slideDown: 'layer-anim-slide-down-out',
        slideLeft: 'layer-anim-slide-left-out',
        slideUp: 'layer-anim-slide-up-out',
        slideRight: 'layer-anim-slide-right-out',
      }[options.anim] || 'layer-anim-close';

    // 移除主容器
    var remove = function () {
      var WRAP = 'layui-layer-wrap';

      // 是否关闭时隐藏弹层容器
      if (hideOnClose) {
        layero.removeClass('layer-anim ' + closeAnim);
        return layero.hide();
      }

      // 是否为页面捕获层
      if (type === ready.type[1] && layero.attr('conType') === 'object') {
        layero.children(':not(.' + doms[5] + ')').remove();
        var wrap = layero.find('.' + WRAP);
        for (var i = 0; i < 2; i++) {
          wrap.unwrap();
        }
        wrap.css('display', wrap.data('display')).removeClass(WRAP);
      } else {
        // 低版本 IE 回收 iframe
        if (type === ready.type[2]) {
          try {
            var iframe = $('#' + doms[4] + index)[0];
            iframe.contentWindow.document.write('');
            iframe.contentWindow.close();
            layero.find('.' + doms[5])[0].removeChild(iframe);
          } catch {
            // ignore
          }
        }
        layero[0].innerHTML = '';
        layero.remove();
      }

      typeof ready.end[index] === 'function' && ready.end[index]();
      delete ready.end[index];
      typeof callback === 'function' && callback();

      // 移除 reisze 事件
      if (ready.events.resize[index]) {
        win.off('resize', ready.events.resize[index]);
        delete ready.events.resize[index];
      }
    };
    // 移除遮罩
    var shadeo = $('#' + doms.SHADE + index);
    if ((layer.ie && layer.ie < 10) || !options.isOutAnim) {
      shadeo[hideOnClose ? 'hide' : 'remove']();
    } else {
      shadeo.css({ opacity: 0 });
      setTimeout(function () {
        shadeo[hideOnClose ? 'hide' : 'remove']();
      }, 350);
    }

    // 是否允许关闭动画
    if (options.isOutAnim) {
      layero.addClass('layer-anim ' + closeAnim);
    }

    ready.restScrollbar(index);

    // 记住被关闭层的最小化堆叠坐标
    if (typeof layero.attr('minLeft') === 'string') {
      ready.minStackIndex--;
      ready.minStackArr.push(layero.attr('minLeft'));
    }

    if ((layer.ie && layer.ie < 10) || !options.isOutAnim) {
      remove();
    } else {
      setTimeout(function () {
        remove();
      }, 200);
    }
  };

  if (!hideOnClose && typeof ready.beforeEnd[index] === 'function') {
    ready.promiseLikeResolve(ready.beforeEnd[index]()).then(
      function (result) {
        if (result !== false) {
          delete ready.beforeEnd[index];
          executor();
        }
      },
      function (reason) {
        reason !== undefined &&
          window.console &&
          window.console.error('layer error hint: ' + reason);
      },
    );
  } else {
    delete ready.beforeEnd[index];
    executor();
  }
};

// 关闭所有层
layer.closeAll = function (type, callback) {
  if (typeof type === 'function') {
    callback = type;
    type = null;
  }
  var domsElem = $('.' + doms[0]);
  $.each(domsElem, function (_index) {
    var othis = $(this);
    var is = type ? othis.attr('type') === type : 1;
    is &&
      layer.close(
        othis.attr('times'),
        _index === domsElem.length - 1 ? callback : null,
      );
    is = null;
  });
  if (domsElem.length === 0) typeof callback === 'function' && callback();
};

// 根据弹层类型关闭最近打开的层
layer.closeLast = function (type, callback) {
  var layerIndexList = [];
  var isArrayType = $.isArray(type);
  $(typeof type === 'string' ? '.layui-layer-' + type : '.layui-layer').each(
    function (i, el) {
      var layero = $(el);
      var shouldSkip =
        (isArrayType && type.indexOf(layero.attr('type')) === -1) ||
        layero.css('display') === 'none';
      if (shouldSkip) return true;
      layerIndexList.push(Number(layero.attr('times')));
    },
  );
  if (layerIndexList.length > 0) {
    var layerIndexMax = Math.max.apply(null, layerIndexList);
    layer.close(layerIndexMax, callback);
  }
};

/*
 * 拓展模块，layui 开始合并在一起
 */

var cache = layer.cache || {};
var skin = function (type) {
  return cache.skin ? ' ' + cache.skin + ' ' + cache.skin + '-' + type : '';
};

// 仿系统 prompt
layer.prompt = function (options, yes) {
  var style = '';
  var placeholder = '';
  options = options || {};

  // 兼容旧版参数
  var legacyTypeMap = {
    0: 'text',
    1: 'password',
    2: 'textarea',
  };
  if (options.formType in legacyTypeMap) {
    options.formType = legacyTypeMap[options.formType];
  }

  if (typeof options === 'function') yes = options;

  if (options.area) {
    var area = options.area;
    style = 'style="width: ' + area[0] + '; height: ' + area[1] + ';"';
    delete options.area;
  }
  if (options.placeholder) {
    placeholder = ' placeholder="' + options.placeholder + '"';
  }
  var prompt;
  var content =
    options.formType == 'textarea'
      ? '<textarea class="layui-layer-input"' +
        style +
        placeholder +
        '></textarea>'
      : (function () {
          return (
            '<input type="' +
            (options.formType || 'text') +
            '" class="layui-layer-input"' +
            placeholder +
            '>'
          );
        })();

  var success = options.success;
  delete options.success;

  return layer.open(
    $.extend(
      {
        type: 1,
        btn: [i18n.$t('layer.confirm'), i18n.$t('layer.cancel')],
        content: content,
        skin: 'layui-layer-prompt' + skin('prompt'),
        maxWidth: win.width(),
        success: function (layero) {
          prompt = layero.find('.layui-layer-input');
          prompt.val(options.value || '').focus();
          typeof success === 'function' && success(layero);
        },
        resize: false,
        yes: function (index) {
          var value = prompt.val();
          if (value.length > (options.maxlength || 500)) {
            layer.tips(
              i18n.$t('layer.prompt.InputLengthPrompt', {
                length: options.maxlength || 500,
              }),
              prompt,
              { tips: 1 },
            );
          } else {
            yes && yes(value, index, prompt);
          }
        },
      },
      options,
    ),
  );
};

// tab 层
layer.tab = function (options) {
  options = options || {};

  var tab = options.tab || {};
  var THIS = 'layui-this';
  var success = options.success;

  delete options.success;

  return layer.open(
    $.extend(
      {
        type: 1,
        skin: 'layui-layer-tab' + skin('tab'),
        resize: false,
        title: (function () {
          var len = tab.length,
            ii = 1,
            str = '';
          if (len > 0) {
            str = '<span class="' + THIS + '">' + tab[0].title + '</span>';
            for (; ii < len; ii++) {
              str += '<span>' + tab[ii].title + '</span>';
            }
          }
          return str;
        })(),
        content:
          '<ul class="layui-layer-tabmain">' +
          (function () {
            var len = tab.length,
              ii = 1,
              str = '';
            if (len > 0) {
              str =
                '<li class="layui-layer-tabli ' +
                THIS +
                '">' +
                (tab[0].content || 'no content') +
                '</li>';
              for (; ii < len; ii++) {
                str +=
                  '<li class="layui-layer-tabli">' +
                  (tab[ii].content || 'no  content') +
                  '</li>';
              }
            }
            return str;
          })() +
          '</ul>',
        success: function (layero) {
          var btn = layero.find('.layui-layer-title').children();
          var main = layero.find('.layui-layer-tabmain').children();
          btn.on('mousedown', function (e) {
            e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true);
            var othis = $(this),
              index = othis.index();
            othis.addClass(THIS).siblings().removeClass(THIS);
            main.eq(index).show().siblings().hide();
            typeof options.change === 'function' && options.change(index);
          });
          typeof success === 'function' && success(layero);
        },
      },
      options,
    ),
  );
};

// 图片层
layer.photos = function (options, loop, key) {
  var dict = {};

  // 默认属性
  options = $.extend(
    true,
    {
      toolbar: true,
      footer: true,
    },
    options,
  );

  if (!options.photos) return;

  // 若 photos 并非选择器或 jQuery 对象，则为普通 object
  var isObject = !(
    typeof options.photos === 'string' || options.photos instanceof $
  );
  var photos = isObject ? options.photos : {};
  var data = photos.data || [];
  var start = photos.start || 0;
  var success = options.success;

  dict.imgIndex = (start | 0) + 1;
  options.img = options.img || 'img';
  delete options.success;

  // 若 options.photos 不是一个对象
  if (!isObject) {
    // 页面直接获取
    var parent = $(options.photos),
      pushData = function () {
        data = [];
        parent.find(options.img).each(function (index) {
          var othis = $(this);
          othis.attr('layer-index', index);
          data.push({
            alt: othis.attr('alt'),
            pid: othis.attr('layer-pid'),
            src:
              othis.attr('lay-src') ||
              othis.attr('layer-src') ||
              othis.attr('src'),
            thumb: othis.attr('src'),
          });
        });
      };

    pushData();

    loop ||
      parent.on('click', options.img, function () {
        pushData();
        var othis = $(this),
          index = othis.attr('layer-index');
        layer.photos(
          $.extend(options, {
            photos: {
              start: index,
              data: data,
              tab: options.tab,
            },
            full: options.full,
          }),
          true,
        );
      });

    // 不直接弹出
    if (!loop) return;
  } else if (data.length === 0) {
    return layer.msg(i18n.$t('layer.photos.noData'));
  }

  // 上一张
  dict.imgprev = function (key) {
    dict.imgIndex--;
    if (dict.imgIndex < 1) {
      dict.imgIndex = data.length;
    }
    dict.tabimg(key);
  };

  // 下一张
  dict.imgnext = function (key, errorMsg) {
    dict.imgIndex++;
    if (dict.imgIndex > data.length) {
      dict.imgIndex = 1;
      if (errorMsg) {
        return;
      }
    }
    dict.tabimg(key);
  };

  // 方向键
  dict.keyup = function (event) {
    if (!dict.end) {
      var code = event.keyCode;
      event.preventDefault();
      if (code === 37) {
        dict.imgprev(true);
      } else if (code === 39) {
        dict.imgnext(true);
      } else if (code === 27) {
        layer.close(dict.index);
      }
    }
  };

  // 切换
  dict.tabimg = function (key) {
    if (data.length <= 1) return;
    photos.start = dict.imgIndex - 1;
    layer.close(dict.index);
    return layer.photos(options, true, key);
  };

  dict.isNumber = function (n) {
    return typeof n === 'number' && !isNaN(n);
  };

  dict.image = {};

  dict.getTransform = function (opts) {
    var transforms = [];
    var rotate = opts.rotate;
    var scaleX = opts.scaleX;
    var scale = opts.scale;

    if (dict.isNumber(rotate) && rotate !== 0) {
      transforms.push('rotate(' + rotate + 'deg)');
    }

    if (dict.isNumber(scaleX) && scaleX !== 1) {
      transforms.push('scaleX(' + scaleX + ')');
    }

    if (dict.isNumber(scale)) {
      transforms.push('scale(' + scale + ')');
    }

    return transforms.length ? transforms.join(' ') : 'none';
  };

  // 一些动作
  dict.event = function (layero, index, that) {
    // 上一张
    dict.main.find('.layui-layer-photos-prev').on('click', function (event) {
      event.preventDefault();
      dict.imgprev(true);
    });

    // 下一张
    dict.main.find('.layui-layer-photos-next').on('click', function (event) {
      event.preventDefault();
      dict.imgnext(true);
    });

    $(document).on('keyup', dict.keyup);

    // 头部工具栏事件
    layero.off('click').on('click', '*[toolbar-event]', function () {
      var othis = $(this);
      var event = othis.attr('toolbar-event');
      switch (event) {
        case 'rotate':
          dict.image.rotate =
            ((dict.image.rotate || 0) + Number(othis.attr('data-option'))) %
            360;
          dict.imgElem.css({
            transform: dict.getTransform(dict.image),
          });
          break;
        case 'scalex':
          dict.image.scaleX = dict.image.scaleX === -1 ? 1 : -1;
          dict.imgElem.css({
            transform: dict.getTransform(dict.image),
          });
          break;
        case 'zoom':
          var ratio = Number(othis.attr('data-option'));
          dict.image.scale = (dict.image.scale || 1) + ratio;
          // 缩小状态最小值
          if (ratio < 0 && dict.image.scale < 0 - ratio) {
            dict.image.scale = 0 - ratio;
          }
          dict.imgElem.css({
            transform: dict.getTransform(dict.image),
          });
          break;
        case 'reset':
          dict.image.scaleX = 1;
          dict.image.scale = 1;
          dict.image.rotate = 0;
          dict.imgElem.css({
            transform: 'none',
          });
          break;
        case 'close':
          layer.close(index);
          break;
      }
      that.offset();
      that.auto(index);
    });

    // 鼠标滚轮缩放图片事件
    dict.main.on('mousewheel DOMMouseScroll', function (e) {
      var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail;
      var zoomElem = dict.main.find('[toolbar-event="zoom"]');
      if (delta > 0) {
        zoomElem.eq(0).trigger('click');
      } else {
        zoomElem.eq(1).trigger('click');
      }
      e.preventDefault();
    });

    // 滑动切换图片事件
    var touchEndCallback = function (e, state) {
      var duration = Date.now() - state.timeStart;
      var speed = state.distanceX / duration;
      var threshold = win.width() / 3;
      var shouldSwipe =
        Math.abs(speed) > 0.25 || Math.abs(state.distanceX) > threshold;
      if (!shouldSwipe) return;
      if (state.direction === 'left') {
        dict.imgnext(true);
      } else if (state.direction === 'right') {
        dict.imgprev(true);
      }
    };

    $.each([that.shadeo, dict.main], function (i, elem) {
      lay.touchSwipe(elem, {
        onTouchEnd: touchEndCallback,
      });
    });
  };

  // 图片预加载
  function loadImage(url, callback, error) {
    var img = new Image();
    img.src = url;
    if (img.complete) {
      return callback(img);
    }
    img.onload = function () {
      img.onload = null;
      callback(img);
    };
    img.onerror = function (e) {
      img.onerror = null;
      error(e);
    };
  }

  dict.loadi = layer.load(1, {
    shade: 'shade' in options ? false : [0.9, undefined, 'unset'],
    scrollbar: false,
  });

  loadImage(
    data[start].src,
    function (img) {
      layer.close(dict.loadi);

      var alt = data[start].alt || '';

      // 切换图片时不出现动画
      if (key) options.anim = -1;

      // 弹出图片层
      dict.index = layer.open(
        $.extend(
          {
            type: 1,
            id: 'layui-layer-photos',
            area: (function () {
              var imgarea = [img.width, img.height];
              var winarea = [$(window).width() - 100, $(window).height() - 100];

              // 若实际图片的宽或者高比 屏幕大（那么进行缩放）
              if (
                !options.full &&
                (imgarea[0] > winarea[0] || imgarea[1] > winarea[1])
              ) {
                var wh = [imgarea[0] / winarea[0], imgarea[1] / winarea[1]]; // 取宽度缩放比例、高度缩放比例
                if (wh[0] > wh[1]) {
                  // 取缩放比例最大的进行缩放
                  imgarea[0] = imgarea[0] / wh[0];
                  imgarea[1] = imgarea[1] / wh[0];
                } else if (wh[0] < wh[1]) {
                  imgarea[0] = imgarea[0] / wh[1];
                  imgarea[1] = imgarea[1] / wh[1];
                }
              }

              return [imgarea[0] + 'px', imgarea[1] + 'px'];
            })(),
            title: false,
            shade: [0.9, undefined, 'unset'],
            shadeClose: true,
            closeBtn: false,
            move: '.layer-layer-photos-main img',
            moveType: 1,
            scrollbar: false,
            moveOut: true,
            anim: 5,
            isOutAnim: false,
            skin: 'layui-layer-photos' + skin('photos'),
            content:
              '<div class="layer-layer-photos-main">' +
              '<img src="' +
              data[start].src +
              '" alt="' +
              alt +
              '" layer-pid="' +
              (data[start].pid || '') +
              '">' +
              (function () {
                var arr = ['<div class="layui-layer-photos-pointer">'];

                // 左右箭头翻页
                if (data.length > 1) {
                  arr.push(
                    [
                      '<div class="layer-layer-photos-page">',
                      '<span class="layui-icon layui-icon-left layui-layer-photos-prev"></span>',
                      '<span class="layui-icon layui-icon-right layui-layer-photos-next"></span>',
                      '</div>',
                    ].join(''),
                  );
                }

                // 头部工具栏
                if (options.toolbar) {
                  arr.push(
                    [
                      '<div class="layui-layer-photos-toolbar layui-layer-photos-header">',
                      '<span toolbar-event="rotate" data-option="90" title="' +
                        i18n.$t('layer.photos.tools.rotate') +
                        '"><i class="layui-icon layui-icon-refresh"></i></span>',
                      '<span toolbar-event="scalex" title="' +
                        i18n.$t('layer.photos.tools.scaleX') +
                        '"><i class="layui-icon layui-icon-slider"></i></span>',
                      '<span toolbar-event="zoom" data-option="0.1" title="' +
                        i18n.$t('layer.photos.tools.zoomIn') +
                        '"><i class="layui-icon layui-icon-add-circle"></i></span>',
                      '<span toolbar-event="zoom" data-option="-0.1" title="' +
                        i18n.$t('layer.photos.tools.zoomOut') +
                        '"><i class="layui-icon layui-icon-reduce-circle"></i></span>',
                      '<span toolbar-event="reset" title="' +
                        i18n.$t('layer.photos.tools.reset') +
                        '"><i class="layui-icon layui-icon-refresh-1"></i></span>',
                      '<span toolbar-event="close" title="' +
                        i18n.$t('layer.photos.tools.close') +
                        '"><i class="layui-icon layui-icon-close"></i></span>',
                      '</div>',
                    ].join(''),
                  );
                }

                // 底部栏
                if (options.footer) {
                  arr.push(
                    [
                      '<div class="layui-layer-photos-toolbar layui-layer-photos-footer">',
                      '<h3>' + alt + '</h3>',
                      '<em>' + dict.imgIndex + ' / ' + data.length + '</em>',
                      '<a href="' +
                        data[start].src +
                        '" target="_blank">' +
                        i18n.$t('layer.photos.viewPicture') +
                        '</a>',
                      '</div>',
                    ].join(''),
                  );
                }

                arr.push('</div>');
                return arr.join('');
              })() +
              '</div>',
            success: function (layero, index, that) {
              dict.main = layero.find('.layer-layer-photos-main');
              dict.footer = layero.find('.layui-layer-photos-footer');
              dict.imgElem = dict.main.children('img');
              dict.event(layero, index, that);
              options.tab && options.tab(data[start], layero);
              typeof success === 'function' && success(layero);
            },
            end: function () {
              dict.end = true;
              $(document).off('keyup', dict.keyup);
            },
          },
          options,
        ),
      );
    },
    function () {
      layer.close(dict.loadi);
      layer.msg(
        '<span style="white-space: pre-line;">' +
          i18n.$t('layer.photos.urlError.prompt') +
          '</span>',
        {
          time: 30000,
          btn: [
            i18n.$t('layer.photos.urlError.confirm'),
            i18n.$t('layer.photos.urlError.cancel'),
          ],
          yes: function () {
            data.length > 1 && dict.imgnext(true, true);
          },
        },
      );
    },
  );
};

// 主入口
ready.run = function (_$) {
  var $ = _$;
  win = $(window);

  // 移动端兼容性处理
  // https://gitee.com/layui/layui/issues/I81WGC
  // https://github.com/jquery/jquery/issues/1729
  var agent = navigator.userAgent.toLowerCase();
  var isMobile = /android|iphone|ipod|ipad|ios/.test(agent);
  var _win = $(window);
  if (isMobile) {
    $.each(
      { Height: 'height', Width: 'width' },
      function (propSuffix, funcName) {
        var propName = 'inner' + propSuffix;
        win[funcName] = function () {
          return propName in window ? window[propName] : _win[funcName]();
        };
      },
    );
  }
  doms.html = $('html');
  layer.open = function (deliver) {
    var o = new Class(deliver);
    return o.index;
  };
};

layer.path = layui.cache.dir;
layer.ready();
ready.run($);

export { layer };
